package com.cloudlead.common.worker.web;

import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.FilterHolder;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.glassfish.jersey.servlet.ServletContainer;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.filter.CharacterEncodingFilter;

import javax.servlet.DispatcherType;
import javax.servlet.Filter;
import javax.servlet.Servlet;
import java.net.InetSocketAddress;
import java.util.EnumSet;
import java.util.EventListener;

/**
 * 标准spring 配置（java config） 嵌入式jetty9启动
 *
 * @author dean
 * @time 2015年01月22日
 */
public class SimpleServer {
    public static final int DEFAULT_SERVER_PORT = 8080;
    public static final String DEFAULT_CONTEXT_PATH = "/";
    public static final Class DEFAULT_SPRING_ROOT = SpringRootConfiguration.class;
    public static final String JERSEY_CONTAINER_PATH = "/resources/*";

    protected final String serverHost;

    protected final int serverPort;

    protected final String contextPath;

    protected Class<?> springRootConfiguration = null;

    protected final Server server;

    protected ServletContextHandler context;

    protected AnnotationConfigWebApplicationContext springContext;

    public SimpleServer() {
        this(null, DEFAULT_SERVER_PORT, DEFAULT_CONTEXT_PATH, DEFAULT_SPRING_ROOT);
    }

    public SimpleServer(String serverHost, int serverPort) {
        this(serverHost, serverPort, DEFAULT_CONTEXT_PATH, DEFAULT_SPRING_ROOT);
    }

    public SimpleServer(String serverHost, int serverPort, String contextPath) {
        this(serverHost, serverPort, contextPath, DEFAULT_SPRING_ROOT);
    }

    public SimpleServer(String serverHost, int serverPort, String contextPath,
                        Class<?> springRootConfiguration) {
        this.serverHost = serverHost;
        this.serverPort = serverPort;
        this.contextPath = contextPath;
        this.springRootConfiguration = springRootConfiguration;

        InetSocketAddress addr = new InetSocketAddress(serverPort);
        if (null != serverHost) {
            addr = new InetSocketAddress(serverHost, serverPort);
        }
        server = new Server(addr);
        // 设置在JVM退出时关闭Jetty的钩子。
        server.setStopAtShutdown(true);

        setContext(contextPath);

        registerSpringContext();

        registerJerseyContainer();

        addUTF8EncodingFilter();
    }

    protected void setContext(String contextPath) {
        context = new ServletContextHandler(ServletContextHandler.SESSIONS);
        context.setContextPath(contextPath);
        server.setHandler(context);
    }

    private void registerJerseyContainer() {
        ServletContainer servletContainer = new ServletContainer(
                new WebApplication());
        context.addServlet(new ServletHolder(servletContainer), JERSEY_CONTAINER_PATH);
    }

    private void registerSpringContext() {
        if (null != springRootConfiguration) {
            springContext = new AnnotationConfigWebApplicationContext();
            springContext.register(this.springRootConfiguration);
            springContext.addBeanFactoryPostProcessor(new RemoteServiceBeanDefinitionRegistryPostProcessor("com.cloudlead"));
            context.addEventListener(new ContextLoaderListener(springContext));
        }
    }

    private void addUTF8EncodingFilter() {
        FilterHolder characterEncodingHolder = new FilterHolder(
                new CharacterEncodingFilter());
        characterEncodingHolder.setAsyncSupported(true);
        characterEncodingHolder.setInitParameter("encoding", "UTF-8");
        characterEncodingHolder.setInitParameter("forceEncoding", "true");
        addFilter(characterEncodingHolder, "/*");
    }

    public ServletHolder addServlet(Class<? extends Servlet> servlet, String pathSpec) {
        return context.addServlet(servlet, pathSpec);
    }

    public void addServlet(ServletHolder servlet, String pathSpec) {
        context.addServlet(servlet, pathSpec);
    }

    public FilterHolder addFilter(Class<? extends Filter> filter, String pathSpec) {
        EnumSet<DispatcherType> dispatches = EnumSet.of(DispatcherType.REQUEST);
        return context.addFilter(filter, pathSpec, dispatches);
    }

    public void addFilter(FilterHolder filter, String pathSpec) {
        EnumSet<DispatcherType> dispatches = EnumSet.of(DispatcherType.REQUEST);
        context.addFilter(filter, pathSpec, dispatches);
    }

    public void addEventListener(EventListener listener) {
        context.addEventListener(listener);
    }

    public void start() throws Exception {
        if (server != null) {
            if (server.isStarting() || server.isStarted() || server.isRunning()) {
                return;
            }
        }
        server.start();
    }

    public void stop() throws Exception {
        if (server != null) {
            if (server.isRunning()) {
                server.stop();
            }
        }
    }

    public void join() throws InterruptedException {
        if (server != null) {
            server.join();
        }
    }

    public ServletContextHandler getContext() {
        return context;
    }

    @Configuration
    @ComponentScan("com.cloudlead")
    @ImportResource("classpath*:META-INF/spring/*.xml")
    public static class SpringRootConfiguration {

    }

    public static void main(String[] args) throws Exception {
        SimpleServer server = new SimpleServer();
        server.start();
    }
}
